package restless.core.gameObjs {
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.filters.BitmapFilter;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.geom.Vector3D;
	import restless.core.RLEFlashAnimationPoint;
	
	import restless.utilities.display.RLEDisplayObjUtils;
	import restless.utilities.display.RLEMatrixTransformer;
	
	/**
	 * 
	 * @author Jordan Laine
	 * 
	 */
	
	public class RLEBlitMC extends RLEManagedObj {
		
		protected var movieClip:MovieClip;
		protected var tempFAP:RLEFlashAnimationPoint;
		
		protected var nCurrentFrame:int = 1;
		protected var nAnimationCount:int = 0;
		protected var nAnimationDelay:int = 1;		
		protected var bLoopCounter:Boolean = false;
		protected var nLoopCount:int = 0;
		
		private var vBitmapData:Vector.<BitmapData>;
		private var vFAP:Vector.<RLEFlashAnimationPoint> = new Vector.<RLEFlashAnimationPoint>;
		private var vFAPID:Vector.<String> = new Vector.<String>;
		private var matrix:Matrix = new Matrix();
		
		private var _lastFrame:int;
		private var _frames:int;
		private var _framesPerTick:int = 1;
		private var _bitmapSize:Boolean = true;
		private var _mask:Rectangle = null;
		private var _lastRotation:Number = 0;
		private var _vectorBlit:Boolean = false;
		private var _transform:Boolean = false;
		private var _smooth:Boolean = false;
		private var _flash:Boolean = false;
		private var _reverse:Boolean = false;
		private var _repeate:Boolean = false;
		private var _repeateBackwards:Boolean = false;
		private var _stop:Boolean = false;
		private var _vectorParsed:Boolean = false;
		private var _flipped:Boolean = false;
		private var tempX:Number;
		private var tempY:Number;
		
		public override function update():void {
			nAnimationCount++;
			if (nAnimationDelay < nAnimationCount) {
				nAnimationCount = 0;
				if (!_stop) {
					_lastFrame = nCurrentFrame;	
					if (!_reverse) {
						if (nCurrentFrame + _framesPerTick <= _frames) {
							nCurrentFrame += _framesPerTick;
						} else {
							if (_repeate) {
								if (_repeateBackwards) {
									_reverse = true;
									nCurrentFrame -= _framesPerTick;
								} else {
									nCurrentFrame = 1;
								}
							} else {
								nCurrentFrame = _frames;
								_stop = true;
							}
						}
					} else {
						if (nCurrentFrame > _framesPerTick) {
							nCurrentFrame -= _framesPerTick;
						} else {
							_reverse = false;
							nCurrentFrame = 1;
						}
					}
				}
			}
			
			if (rendering) { onCamera(); }
			
		}
		
		public override function render():void {
			if (_lastFrame == nCurrentFrame) { return; }
			
			if (_vectorBlit) {
				tempBitmapData = vBitmapData[nCurrentFrame-1];
				tempPoint.x = 0;
				tempPoint.y = 0;
				if (sID == "pig") {
					//trace ("colorTransform = " + bColorTransform);
				}
				
				if (bFilter) {
					for (i = 0; i > _filter.length - 1; i++) {
						tempBitmapData.applyFilter(tempBitmapData, tempBitmapData.rect, tempPoint, _filter[i]);
					}
				}
				
				if (!_transform) {
					if (_bitmapSize) {
						bitmapData = new BitmapData(tempBitmapData.width, tempBitmapData.height, true, 0x00000000);
					} else {
						bitmapData = new BitmapData(renderRect.width, renderRect.height, true, 0x00000000);
					}
					
					if (bColorTransform) {
						bitmapData.colorTransform(bitmapData.rect, colorTransform);
					}
					
					bitmapData.lock();
					bitmapData.copyPixels(tempBitmapData, tempBitmapData.rect, tempPoint, tempBitmapData, null, true );
					bitmapData.unlock();
				} else {
					if (_bitmapSize) {
						bitmapData = new BitmapData(tempBitmapData.width * scaleX, tempBitmapData.height * scaleY, true, 0x00000000);
					} else {
						bitmapData = new BitmapData(renderRect.width, renderRect.height, true, 0x00000000);
					}
					bitmapData.draw(tempBitmapData, transformMatrix, colorTransform, null, _mask, _smooth);
				}
				
			} else {
				movieClip.gotoAndStop(nCurrentFrame);
				bitmapData = new BitmapData(movieClip.width, movieClip.height, true, 0x00000000);
				
				if (!_transform) {
					bitmapData.draw(movieClip, null, null, null, _mask, _smooth);
				} else {
					matrix = RLEMatrixTransformer.createScaleMatrix(scaleX, scaleY);
					if (rotation != 0) {
						RLEMatrixTransformer.rotateAroundInternalPoint(matrix, x, y, rotation);
					}
					matrix.translate(rect.x, rect.y);
					bitmapData.draw(movieClip, matrix, null, null, _mask, _smooth);
				}
				
				if (bFilter) {
					for (i = 0; i > _filter.length - 1; i++) {
						bitmapData.applyFilter(tempBitmapData, tempBitmapData.rect, tempPoint, _filter[i]);
					}
				}
			}
			
			updateCenterXY();
			
			if (_bitmapSize) {
				width = bitmapData.width;
				height = bitmapData.height;
				setRenderBoundary(width, height);
			}
		}
		
		protected function flipBitmapData(x:Boolean = true):void {
			_flipped = !_flipped;
			
			if (x) {
				//matrix.transformPoint
				matrix = new Matrix( -1, 0, 0, 1, width, 0);
			} else {
				matrix = new Matrix( 1, 0, 0, -1, 0, height);
			}
			
			tempBitmapData = bitmapData;
			bitmapData = new BitmapData(width, height, true, 0x000000000);
			bitmapData.draw(tempBitmapData, matrix, null, null, null, _smooth);
			if (_flipped) { 
				if (x) { this.x += centerX; }
				else { this.y += centerY;}
			} else { 
				if (x) { this.x -= centerX; }
				else { this.y -= centerY; }
			}
			
			//y += centerY;
		}
		
		final public function switchGFXMC(mc:MovieClip, center:Boolean = false, repeate:Boolean = false, reverse:Boolean = false, startFrame:int = 1):void {
			_repeate = repeate;
			_reverse = reverse;
			_vectorBlit = false; 
			
			movieClip = mc;
			_frames = movieClip.totalFrames;
			setFrame(startFrame);
			this.center = center;
			forceRender();
		}
		
		final public function switchGFX(vBitData:Vector.<BitmapData>, center:Boolean = false, repeate:Boolean = false, reverse:Boolean = false, startFrame:int = 1):void {
			_repeate = repeate;
			_reverse = reverse;
			_vectorBlit = true;
			
			vBitmapData = vBitData;
			_frames = vBitmapData.length;
			setFrame(startFrame);
			this.center = center;
			forceRender();
		}
		
		final public function flash(durration:int, interval:int):void {
			//shouldItTimer(true);
			// use filters for this
		}
		
		override public function forceRender():void {
			_lastFrame = -1;
			super.forceRender();
			updateCenterXY();
			_lastFrame = nCurrentFrame;
		}
		
		public function setFrame(num:int):void {
			if (num > _frames) {
				nCurrentFrame = _frames - 1;
			} else if (num < 1) {
				nCurrentFrame = 1;
			} else {
				nCurrentFrame = num;
			}
			
		}
		
		override public function setScale(x:Number = 0, y:Number = 0):void {
			if (x == 0 && y == 0) {
				return;
			}
			
			if (x == 1 && y == 1 && rotation == 0) {
				_transform = false;
			} else  {
				_transform = true;	
			}
			
			super.setScale(x, y)
			forceRender();
		}
		
		public function setSingleImage(bitData:BitmapData, center:Boolean = false):void {
			if (vBitmapData == null) { vBitmapData = new Vector.<BitmapData>; }
			else { vBitmapData.length = 0; }
			tempBitmapData = bitData;
			vBitmapData.push(tempBitmapData);
			_vectorBlit = true; 
			_frames = 1;
			setFrame(1);
			this.center = center;
			forceRender();
		}
		
		override public function set rotation(rot:Number):void {
			var tempRot:Number = rot;
			if (rot == 0) {
				if (super.rotation != 0) {
					super.rotation = tempRot;
					if (scaleX == 1 && scaleY == 1) {
						_transform = false;
						forceRender();
					}
				}
				return;
			} else {
				while (tempRot > 360) {
					tempRot -= 360;
				}
				while (rotation < 0) {
					tempRot += 360;
				}
				if (tempRot != super.rotation) {
					super.rotation = tempRot;
					_transform = true;
					forceRender();
				}
			}
		}
		
		protected function onCamera():void {
			screenM.onCamera(this);
		}
		
		//not functional with vBitmaps yet
		public function set mask(rect:Rectangle):void {
			_mask = rect;
		}
		
		public function get mask():Rectangle {
			return _mask;
		}
		
		//Faster than insideRect
		override public function hitTestPoint(point:Point):Boolean {
			tempPoint.x = rect.x;
			tempPoint.y = rect.y;
			
			return bitmapData.hitTest(tempPoint, 255, point);
			
		}
		
		public function hitTestBitmapData(bd:BitmapData, bdPoint:Point):Boolean {
			tempPoint.x = rect.x;
			tempPoint.y = rect.y;
			
			return bitmapData.hitTest(tempPoint, 255, bd, bdPoint );
		}
		
		public function set stop(bool:Boolean):void {
			_stop = bool;
		}
		
		public function get stop():Boolean {
			return _stop;
		}
		
		public function getMC():MovieClip {
			if (movieClip != null) {
				return movieClip;
			} else {
				return null;
				throw Error("No MovieClip Loaded");
			}
		}
		
		public function set animationDelay(num:int):void {
			nAnimationDelay = num;
		}
		
		public function get animationDelay():int {
			return nAnimationDelay;
		}
		
		public function get totalFrames():int {
			return _frames;
		}
		
		public function set smooth(bool:Boolean):void {
			if (bool == _smooth) { return; }
			_smooth = bool;
		}
		
		public function get smooth():Boolean {
			return _smooth;
		}
		
		public function set reverse(bool:Boolean):void {
			if (bool == _reverse) { return; }
			_reverse = bool;
		}
		
		public function get reverse():Boolean {
			return _reverse;
		}
		
		public function set bitmapSizedRender(bool:Boolean):void {
			if (bool == _bitmapSize) { return; }
			_bitmapSize = bool;
			
			if (!_bitmapSize) {
				setRenderBoundary(width, height);
			}
		}
		
		public function get bitmapSizedRender():Boolean {
			return _bitmapSize;
		}
		
		public function set repeate(bool:Boolean):void {
			if (bool == _repeate) { return; }
			_repeate = bool;
		}
		
		public function get repeate():Boolean {
			return _repeate;
		}
		
		public function get framesPerTick():int {
			return _framesPerTick;
		}
		
		public function set framesPerTick(value:int):void {
			_framesPerTick = value;
		}
		
		public function getFAP(id:String):RLEFlashAnimationPoint {
			var num:int = vFAPID.indexOf(id);
			return vFAP[num];
		}
		
		public function setFAPs(id:String):void {
			vFAP = gfxM.getFAPs(id);
			vFAPID.length = 0;
			var i:int = 0;
			for (i; i <= vFAP.length - 1; i++) {
				vFAPID.push(vFAP[i].id);
			}
		}
		
		public function clearAnimationPoints():void {
			if (vFAP != null) {
				for (i = -1; i < vFAP.length-1; ++i) {
					tempFAP = vFAP[i];
					tempFAP.dispose();
				}
				vFAP = null;
				tempFAP = null;
				vFAPID = null;
			}
			
		}
		
		protected final function clearBitmaps():void {
			vBitmapData = null;
			bitmapData = null;
			tempBitmapData = null;
			
			bitmap = null;
			tempBitmap = null;
		}
		
		override public function isNull():Boolean {
			if (movieClip == null && vBitmapData == null) {
				return true;
			} else {
				return false;
			}
		}
		
		public override function dispose():void {
			clearAnimationPoints();
			clearBitmaps();
			_mask = null;
			matrix = null;
			movieClip = null;
			vBitmapData = null;
			onCamera();
			super.dispose();
		}
	}
}